<!doctype html>
<html>
    <head>
        <title>HT for Web 数据绑定手册</title>
        <meta charset="UTF-8">    
        <meta name="viewport" content="user-scalable=yes, width=1024">
        <style type="text/css"> 
            h1, h2, h3, h4, h5, h6, p, blockquote {
                margin: 0;
                padding: 0;
            }
            body {
                font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
                font-size: 13px;
                line-height: 18px;
                color: #737373;
                background-color: white; 
                margin: 10px 13px 10px 13px;
            }
            table {
                margin: 10px 0 15px 0;
                border-collapse: collapse;
            }
            td,th {	
                border: 1px solid #ddd;
                padding: 3px 10px;
            }
            th {
                padding: 5px 10px;	
            }
            a {
                color: #0069d6;
            }
            a:hover {
                color: #0050a3;
                text-decoration: none;
            }
            a img {
                border: none;
            }
            p {
                margin-bottom: 9px;
            }
            h1, h2, h3, h4, h5, h6 {
                color: #404040;
                line-height: 36px;
            }
            h1 {
                margin-bottom: 18px;
                font-size: 30px;
            }
            h2 {
                font-size: 24px;
            }
            h3 {
                font-size: 18px;
            }
            h4 {
                font-size: 16px;
            }
            h5 {
                font-size: 14px;
            }
            h6 {
                font-size: 13px;
            }
            hr {
                margin: 0 0 19px;
                border: 0;
                border-bottom: 1px solid #ccc;
            }
            blockquote {
                padding: 13px 13px 21px 15px;
                margin-bottom: 18px;
                font-family:georgia,serif;
                font-style: italic;
            }
            blockquote:before {
                content:"\201C";
                font-size:40px;
                margin-left:-10px;
                font-family:georgia,serif;
                color:#eee;
            }
            blockquote p {
                font-size: 14px;
                font-weight: 300;
                line-height: 18px;
                margin-bottom: 0;
                font-style: italic;
            }
            code, pre {
                font-family: Monaco, Andale Mono, Courier New, monospace;
            }
            code {
                background-color: #fee9cc;
                color: rgba(0, 0, 0, 0.75);
                padding: 1px 3px;
                font-size: 12px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
                border-radius: 3px;
            }
            pre {
                display: block;
                padding: 14px;
                margin: 0 0 18px;
                line-height: 16px;
                font-size: 11px;
                border: 1px solid #d9d9d9;
                white-space: pre-wrap;
                word-wrap: break-word;
            }
            pre code {
                background-color: #fff;
                color:#737373;
                font-size: 11px;
                padding: 0;
            }
            sup {
                font-size: 0.83em;
                vertical-align: super;
                line-height: 0;
            }
            * {
                -webkit-print-color-adjust: exact;
            }
            @media screen and (min-width: 914px) {
                body {
                    width: 854px;
                    margin:10px auto;
                }
            }
            @media print {
                body,code,pre code,h1,h2,h3,h4,h5,h6 {
                    color: black;
                }
                table, pre {
                    page-break-inside: avoid;
                }
            }                        
            iframe{
                width: 100%;
                border: 1px solid #34495E;
                margin: 0;                
            }            
            .logo{
                vertical-align: middle;
            }

        </style>        
        <script>
            function init() {
                var logoSrc = '',
                    logos = document.querySelectorAll('.logo'),
                    i = 0;
                for (; i < logos.length; i++) {
                    logos[i].src = logoSrc;
                }
                
                var iframes = document.querySelectorAll('iframe'),
                    func = function(){};
                for (i=0; i < iframes.length; i++) {
                    var iframe = iframes[i];
                    
                    // a small hack to make it work on android
                    iframe.ontouchstart = func;
                    
                    var div = document.createElement('div');
                    div.innerHTML = '<a href="' + iframe.src + '" target="_blank">独立运行→</a>';
                    iframe.parentNode.insertBefore(div, iframe);
                }   
            }
        </script>    
    </head>
    <body onload="init();">
        <a href="http://www.hightopo.com"><img class="logo"></a>HT for Web 数据绑定手册
        <hr style="margin: 1px 0 20px 0">
<p>索引</p>

<ul><li><a href="#ref_overview">概述</a></li><li><a href="#ref_format">绑定格式</a></li><li><a href="#ref_vector">矢量绑定</a><ul><li><a href="#ref_piechart">饼图案例</a></li><li><a href="#ref_switch">开关案例</a></li></ul></li><li><a href="#ref_icons">图标绑定</a></li><li><a href="#ref_shape3dmodel">模型绑定</a><ul><li><a href="#ref_ems">设备案例</a></li><li><a href="#ref_alarm">告警案例</a></li></ul></li></ul>

<hr/>

<div id="ref_overview"></div>

<h2>概述</h2>

<p>数据绑定意味将<code>Data</code>图元的数据模型信息，与界面图形的颜色、大小和角度等可视化参数进行自动同步，
<code>HT</code>的预定于图形组件默认就已与<code>DataModel</code>中的<code>Data</code>数据绑定，例如用户修改<code>Node</code>的<code>position</code>位置值，
则<code>GraphView</code>和<code>Graph3dView</code>上的相应图元位置会自动同步变化。</p>

<p>传统的数据绑定有单向绑定和双向绑定的概念，但<code>HT</code>系统的设计模式使得绑定更加简化易于理解，<code>HT</code>只有一个<code>DataModel</code>数据模型，
绑定<code>DataModel</code>的图形组件并没有组件内部的其他数据模型，所以组件都是如实根据<code>DataModel</code>来呈现界面效果，因此当用户拖拽图元移动时，
本质也是修改了数据模型中<code>Node</code>的<code>position</code>位置值，而该属性变化触发的事件通过模型再次派发到图形组件，引发图形组件根据新的模型信息刷新界面。</p>

<p><code>HT</code>的预定义图元都已自动实现数据绑定，本手册要介绍的主要针对自定义矢量、自定义图标和自定义3d模型，这三种可扩展图形展示效果的数据绑定机制，
这三种自定义图形都具有一致的描述与<code>Data</code>进行数据绑定的<code>json</code>格式，用户只需要根据<code>HT</code>指定的规则格式描述好图元参数绑定的<code>Data</code>属性，
应用中只需要更新<code>Data</code>上的数据，图形界面就会自动刷新，从而达到实时显示数据的效果。</p>

<div id="ref_format"></div>

<h2>绑定格式</h2>

<p>绑定的格式很简单，只需将以前的参数值用一个带<code>func</code>属性的对象替换即可，<code>func</code>的内容有以下几种类型：</p>

<ul><li><code>function</code>类型，直接调用该函数，并传入相关<code>Data</code>和<code>view</code>对象，由函数返回值决定参数值，即<code>func(data, view);</code>调用。</li><li><code>string</code>类型：<ul><li><code>style@***</code>开头，则返回<code>data.getStyle(***)</code>值，其中<code>***</code>代表<code>style</code>的属性名。</li><li><code>attr@***</code>开头，则返回<code>data.getAttr(***)</code>值，其中<code>***</code>代表<code>attr</code>的属性名。</li><li><code>field@***</code>开头，则返回<code>data.***</code>值，其中<code>***</code>代表<code>data</code>的属性名。</li><li>如果不匹配以上情况，则直接将<code>string</code>类型作为<code>data</code>对象的函数名调用data***(view)，返回值作为参数值。</li></ul></li></ul>

<p>除了<code>func</code>属性外，还可设置<code>value</code>属性作为默认值，如果对应的<code>func</code>取得的值为<code>undefined</code>或<code>null</code>时，则会采用<code>value</code>属性定义的默认值。
例如以下代码，如果对应的<code>Data</code>对象的<code>attr</code>属性<code>stateColor</code>为<code>undefined</code>或<code>null</code>时，则会采用<code>yellow</code>颜色：</p>

<pre><code>color: {
    func: &#39;attr@stateColor&#39;,
    value: &#39;yellow&#39;
}</code></pre>

<div id="ref_vector"></div>

<h2>矢量绑定</h2>

<p>数据绑定是<code>HT</code>系统矢量比传统矢量描述格式如<a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a>灵活强大的重要因素，
上文描述的所有矢量组件属性全部可以设置成动态绑定<code>Data</code>模型属性。因此一般的工作流程为：先手工或者采用矢量编辑工具生成矢量<code>json</code>信息，
将需要动态变化的参数设计成数据绑定的格式。运行中只需要修改<code>Data</code>中绑定图形的相关属性，则矢量会自动将绑定的属性值，
转换显示为相应的颜色，大小，角度等图形信息，最终达到松耦合的数据可视化流程架构。</p>

<div id="ref_piechart"></div>

<h3>饼图案例</h3>

<p><iframe src="examples/example_piebinding.html" style="height:230px"></iframe></p>

<p>上例子中：</p>

<ul><li><code>hollow: {func: &#39;style@isHollow&#39;}</code> 将<code>pieChart</code>的<code>hollow</code>属性，绑定到<code>Node</code>对象的<code>style</code>属性<code>isHollowhollow</code>上</li><li><code>startAngle: {func: &#39;attr@angle&#39;}</code> 将<code>pieChart</code>的<code>startAngle</code>属性，绑定到了<code>Node</code>对象的<code>attr</code>属性<code>angle</code>上</li><li><code>height: { func: &#39;field@_height&#39; }</code> 将<code>pieChart</code>的<code>height</code>属性，绑定到了<code>Node</code>对象的<code>field</code>属性<code>_height</code>上</li><li><code>width: { func: &#39;getWidth&#39; }</code> 将<code>pieChart</code>的<code>width</code>属性，绑定到了<code>Node</code>对象的方法<code>getWidth</code>上</li><li><code>rect: { func: function (data) { return [5, 5, 190, 190]; } }</code> 将<code>pieChart</code>的<code>rect</code>属性，绑定到了<code>func</code>属性指定的方法上   </li></ul>

<div id="ref_switch"></div>

<h3>开关案例</h3>

<p>下例展示了颜色<code>background</code>，宽度<code>borderWidth</code>，旋转角度<code>rotation</code>和可见<code>visible</code>多种类型属性，
与<code>Data</code>图元<code>attr</code>属性的数据绑定。</p>

<p><iframe src="examples/example_switch.html" style="height:200px"></iframe></p>

<pre><code>background: {
    value: &#39;#2C3E50&#39;,
    func: &#39;attr@switch.background&#39;
},
visible: {
    value: true,
    func: &#39;attr@switch.visible&#39;
} 
borderWidth: {
    value: 8,
    func: &#39;attr@switch.thickness&#39;
},
rotation: {
    value: -Math.PI/4,
    func: &#39;attr@switch.angle&#39;
}</code></pre>

<div id="ref_icons"></div>

<h2>图标绑定</h2>

<p>图标用于呈现在图元周围作为附属物的展示方式，可参见<a href="../../core/beginners/ht-beginners-guide.html#ref_styleicon">入门手册</a>
和<a href="../../core/3d/ht-3d-guide.html#ref_icons">3D手册</a>的说明，定义图标的参数皆可采用数据绑定的描述方式实现动态变化。</p>

<p><iframe src="examples/example_icons.html" style="height:460px"></iframe></p>

<pre><code>node.addStyleIcon(&#39;alarm&#39;, {                    
    names: [&#39;alarm-star&#39;, &#39;alarm-triangle&#39;, &#39;alarm-circle&#39;],                    
    position: {func: &#39;attr@alarm.position&#39;},
    direction: { func: &#39;attr@alarm.direction&#39; },
    gap: { func: &#39;attr@alarm.gap&#39; },
    width: { func: &#39;attr@alarm.width&#39; },
    height: { func: &#39;attr@alarm.height&#39; },
    visible: { func: &#39;attr@alarm.visible&#39; },                    
    rotation: { func: &#39;attr@alarm.rotation&#39; },
    stretch: { func: &#39;attr@alarm.stretch&#39; },
    opacity: { func: &#39;attr@alarm.opacity&#39; },
    transparent: { func: function(data){ return data.a(&#39;alarm.opacity&#39;) &lt; 1; } },
    light: { func: &#39;attr@alarm.light&#39; },
    textureScale: { func: &#39;attr@alarm.texture.scale&#39; },
    discardSelectable: { func: &#39;attr@alarm.discard.selectable&#39; },
    r3: { func: function(data) { return [0, 0, -data.a(&#39;alarm.rotation&#39;)]; } },
    face: { func: &#39;attr@alarm.face&#39; },
    reverseFlip: { func: &#39;attr@alarm.reverse.flip&#39; },
    reverseCull: { func: &#39;attr@alarm.reverse.cull&#39; },
    reverseColor: { func: &#39;attr@alarm.reverse.color&#39; },
    autorotate: { func: &#39;attr@alarm.autorotate&#39; }
});</code></pre>

<div id="ref_shape3dmodel"></div>

<h2>模型绑定</h2>

<p><a href="../../plugin/modeling/ht-modeling-guide.html#ref_attr">建模手册</a>中介绍的自定义<code>3D</code>模型也支持数据绑定机制，
可数据绑定是<code>HT</code>的建模远强大于传统<code>3D</code>建模工具的特色功能，构建模型的任何颜色、大小、旋转等参数皆可绑定<code>Data</code>数据模型属性，
以这样的方式建模后用户只需要更新<code>Data</code>数据对象属性值，则<code>3D</code>界面对应图元的呈现效果即可实时同步更新。</p>

<div id="ref_ems"></div>

<h3>设备案例</h3>

<p><iframe src="examples/example_ems.html" style="height:450px"></iframe></p>

<p>以上例子注册的<code>ems-block</code>模型由一个立方体和一个圆筒构造，两个模型的颜色分别绑定了<code>Data</code>上<code>attr</code>属性的<code>circleColor</code>和<code>rectColor</code>值：</p>

<pre><code>ht.Default.setShape3dModel(&#39;ems-block&#39;, [
    {
        shape3d: ht.Default.createCylinderModel(32, 0, 32, false, false, true, true),   
        r3: [Math.PI/2, 0, 0],   
        color: {
            func: &#39;attr@circleColor&#39;,
            value: &#39;#3498DB&#39;
        }     
    },
    {
        shape3d: &#39;box&#39;,
        s3: [1, 0.2, 1], 
        t3: [0, -0.7, 0],
        color: {
            func: &#39;attr@rectColor&#39;,
            value: &#39;#3498DB&#39;
        }
    }
]); </code></pre>

<p><code>HT</code>的所有通用组件也都支持对矢量图片的渲染，该例子中左侧<code>TreeView</code>显示的正是实现了数据绑定的矢量图标，
<code>Graph3dView</code>和<code>TreeView</code>的组件都绑定了同样的数据源，因此修改<code>Data</code>上<code>attr</code>属性的<code>circleColor</code>和<code>rectColor</code>可同时驱动不同的视图组件。</p>

<pre><code>ht.Default.setImage(&#39;ems-block&#39;, {
    width: 18,
    height: 18,
    comps: [
        {
            type: &#39;circle&#39;,
            rect: [0, 2, 18, 10],
            background: {
                func: &#39;attr@circleColor&#39;,
                value: &#39;#3498DB&#39;                               
            }
        }, 
        {
            type: &#39;rect&#39;,
            rect: [4, 14, 10, 3],
            background: {
                func: &#39;attr@rectColor&#39;,
                value: &#39;#3498DB&#39;                               
            }
        }                           
]}); </code></pre>

<div id="ref_alarm"></div>

<h3>告警案例</h3>

<p><iframe src="examples/example_alarm.html" style="height:400px"></iframe></p>

<p><code>icons</code>图标功能不仅可显示平面图片，也支持将注册的模型作为图标摆放。以上例子在<code>Node</code>图元顶上摆放了一个<code>3d</code>模型的图标，
该模型有三个部分构成一个告警提示，模型三个部分的颜色绑定了图元<code>style</code>属性的<code>all.blend</code>值，模型的旋转角度绑定了<code>alarm.rotation.*</code>。</p>

<pre><code>var array = [
    {
        shape3d: ringModel,  
        color: { func: &#39;style@all.blend&#39; },
        r3: [Math.PI/2, 0, 0]
    },
    {
        shape3d: sphereModel,
        color: { func: &#39;style@all.blend&#39; },
        t3: [0, 30, 0]
    },
    {
        shape3d: cylinderModel, 
        color: { func: &#39;style@all.blend&#39; },
        t3: [0, -10, 0]
    }
];

ht.Default.setShape3dModel(&#39;alarm&#39;, {
    shape3d: array,                       
    t3: [0, 50, 0],
    r3: {func: function(data){
         return [
             data.a(&#39;alarm.rotation.x&#39;), 
             data.a(&#39;alarm.rotation.y&#39;), 
             data.a(&#39;alarm.rotation.z&#39;)];
    }}
});</code></pre>

<p>图标为<code>3d</code>模型时不同于传统的通过<code>names</code>定义图标数组，而是设置<code>shape3d</code>的模型名称，目前还不支持数组方式，
只允许指定一个模型名称，如需添加多个<code>3d</code>模型图标可通过多次调用<code>addStyleIcon</code>实现：</p>

<pre><code>node.addStyleIcon(&#39;alarm&#39;, {
   position: 3,
   face: &#39;center&#39;,
   shape3d: &#39;alarm&#39;                   
}); </code></pre>    <hr id="contact" style="margin: 20px 0 1px 0">
    <a href="http://www.hightopo.com"><img class="logo"></a>欢迎交流 <a href="mailto:service@hightopo.com">service@hightopo.com</a>
</body>
</html>
